package cn.gjxblog.expression;

import cn.gjxblog.common.Person;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Spring表达式的操作
 */
@RunWith(JUnit4.class)
public class TestExpressionParser {
    String expressionStr = "1 + 2";
    // 定义一个Spel解析器
    SpelExpressionParser parser = new SpelExpressionParser();

    @Test
    public void test1(){
       ;
        Expression expression = parser.parseExpression(expressionStr);
        //方式一 直接计算
        Object value = expression.getValue();
        System.out.println(value.toString());

        System.out.println(parser.parseExpression("T(System).getProperty('user.dir')").getValue());
        System.out.println(parser.parseExpression("T(java.lang.Math).random() * 100.0").getValue());
    }

    @Test
    public void test2(){
        Expression expression = parser.parseExpression(expressionStr);

        //方式二，定义环境变量，环境内计算拿值
        StandardEvaluationContext context = new StandardEvaluationContext();
        System.out.println(expression.getValue(context));
    }

    /**
     * 字符串-语法分析-生成表达式对象-添加执行上下文-执行结果
     *
     * 关于SpEL的几个概念：
     *
     * 表达式（“干什么”）：SpEL的核心，所以表达式语言都是围绕表达式进行的
     * 解析器（“谁来干”）：用于将字符串表达式解析为表达式对象
     * 上下文（“在哪干”）：表达式对象执行的环境，该环境可能定义变量、定义自定义函数、提供类型转换等等
     * root根对象及活动上下文对象（“对谁干”）：root根对象是默认的活动上下文对象，活动上下文对象表示了当前表达式操作的对象
     */


    /**
     * SpEL对Template模板的支持
     */
    @Test
    public void test3(){
        String greetingExp = "Hello, #{#user} ---> #{T(System).getProperty('user.home')}";
        EvaluationContext context = new StandardEvaluationContext();
        context.setVariable("user", "fsx");

        Expression expression = parser.parseExpression(greetingExp, new TemplateParserContext());
        System.out.println(expression.getValue(context, String.class));
    }

    /**
     * EvaluationContext.setVariable 用法
     */
    @Test
    public void test4(){
        Person person = new Person("星曦", 30);

        List<String> list = Arrays.asList("周杰伦","陈奕迅");
        Map<String,Integer> maps = new HashMap<String,Integer>(){{put("周杰伦",40);put("陈奕迅",42);}};

        EvaluationContext context = new StandardEvaluationContext();
        context.setVariable("myPerson", person);
        context.setVariable("myList", list);
        context.setVariable("myMap", maps);

        printExpressionResult("#myPerson",context);
        printExpressionResult("#myPerson.name",context);

        // setVariable方式取值不能像root一样，前缀不可省略~~~~~
        printExpressionResult("#name",context);//null
        // 不写前缀去root找，找到null 再getName属性报错
//        printExpressionResult("name",context);

        printExpressionResult("#myList",context);
        printExpressionResult("#myList[1]",context);

        // 中文作为key必须用''包起来
//        printExpressionResult("#myMap[周杰伦]",context);
        printExpressionResult("#myMap['周杰伦']",context);
    }

    /**
     * #root表达式的使用
     */
    @Test
    public void test5(){
        StandardEvaluationContext context = new StandardEvaluationContext();
        context.setRootObject(new Person("星曦",22));

        printExpressionResult("#root",context);
        printExpressionResult("#root.name",context);
        printExpressionResult("#root.age",context);

        // 若单纯的想获取属性值，不用再使用#，直接属性名即可
        // #root代表把root当作key先去查找出对象，再导航查找。。。。。而不用#类似全文查找
        printExpressionResult("#age",context);//null
        printExpressionResult("age",context);//22

        // el参与计算时，取值方式也可以是#root 或者直接name属性的方式 都是可以的
        printExpressionResult("age == 18",context);//false
        printExpressionResult("#root.age == 22",context);//false
        printExpressionResult("#root.name.equals('星曦')",context);//false

    }



    private void printExpressionResult(String expressionString,EvaluationContext context) {
        System.out.println(parser.parseExpression(expressionString).getValue(context));
    }

}
